#ifndef __VAR__HPP__
#define __VAR__HPP__

#include <tuple>
#include "../common/Helpers.hpp"
// Need this to be a literal type in order to get constexpr working properly
// In particular, Var may not have virtual functions
template <int PLACE, bool is_one = false> struct Var {
  constexpr Var() {
    static_assert((is_one && PLACE == 0) || (!is_one && PLACE > 0),
                  "Default Var constructor is only for the OneVar singleton");
  }

  constexpr size_t place() {return PLACE;}

  template <typename... T>
  constexpr int operator () (std::tuple<T ...> const &vals) const 
  { return (is_one) ? 1 : ConstExprGet<PLACE>()(vals);}
};

template <int PLACE, bool is_constant> 
std::ostream & operator<<(std::ostream &os, const Var<PLACE, is_constant> &c) {
  os << ((is_constant) ? "CONSTANT" : "") << " VAR (place=" << c.place() << ")";
  return os;
}

typedef Var<0, true> Constant;
// typedef Var<false> Variable;
template <int PLACE> using Variable = Var<PLACE, false>;
constexpr Constant OneVar;
#endif //__VAR__HPP__
